package com.ling.pl.security.decision;

import com.ling.pl.security.model.DefaultGroup;
import com.ling.pl.security.model.DefaultOrg;
import com.ling.pl.security.model.DefaultPosition;
import com.ling.pl.security.model.DefaultUser;
import com.ling.pl.security.utils.AttributeType;
import com.ling.pl.security.utils.ConfigAttribute;
import com.ling.pl.security.utils.SecurityConfigAttribute;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

enum GroupVoteType {
    group, user, org, position
}

/**
 * @author bo.wang
 */
public class GroupAccessDecisionVoter extends AbstractAccessDecisionVoter {
    @Override
    protected AttributeType getAttributeType() {
        return AttributeType.group;
    }

    public int vote(DefaultUser authentication, Object object,
                    Collection attributes) {
        int voteResult = voteGroups(authentication, attributes, GroupVoteType.user);
        if (voteResult != ACCESS_ABSTAIN) {
            return voteResult;
        }
        voteResult = voteGroups(authentication, attributes, GroupVoteType.org);
        if (voteResult != ACCESS_ABSTAIN) {
            return voteResult;
        }
        voteResult = voteGroups(authentication, attributes, GroupVoteType.position);
        if (voteResult != ACCESS_ABSTAIN) {
            return voteResult;
        }
        voteResult = voteGroups(authentication, attributes, GroupVoteType.group);
        if (voteResult != ACCESS_ABSTAIN) {
            return voteResult;
        }
        return ACCESS_ABSTAIN;
    }

    private int voteGroups(DefaultUser loginUser, Collection<ConfigAttribute> attributes, GroupVoteType type) {
        for (ConfigAttribute attribute : attributes) {
            SecurityConfigAttribute configAttribute = (SecurityConfigAttribute) attribute;
            AttributeType attributeType = configAttribute.getAttributeType();
            if (!attributeType.equals(AttributeType.group)) {
                continue;
            }
            DefaultGroup group = (DefaultGroup) configAttribute.getMember();
            if (type.equals(GroupVoteType.group)) {
                for (DefaultGroup g : loginUser.getGroups()) {
                    if (group.getId().equals(g.getId())) {
                        if (configAttribute.isGranted()) {
                            return ACCESS_GRANTED;
                        } else {
                            return ACCESS_DENIED;
                        }
                    }
                }
            } else if (type.equals(GroupVoteType.user)) {
                for (DefaultUser user : group.getUsers()) {
                    if (user.getUsername().equals(loginUser.getUsername())) {
                        if (configAttribute.isGranted()) {
                            return ACCESS_GRANTED;
                        } else {
                            return ACCESS_DENIED;
                        }
                    }
                }
            } else if (type.equals(GroupVoteType.org) && loginUser.getOrgs() != null) {
                return decitionOrgs(buildOrgSecurityConfigAttributes(group.getOrgs(), configAttribute.isGranted()), loginUser.getOrgs());
            } else if (type.equals(GroupVoteType.position) && loginUser.getPositions() != null) {
                for (DefaultPosition p : group.getPositions()) {
                    for (DefaultPosition userPosition : loginUser.getPositions()) {
                        if (p.getId().equals(userPosition.getId())) {
                            if (configAttribute.isGranted()) {
                                return ACCESS_GRANTED;
                            } else {
                                return ACCESS_DENIED;
                            }
                        }
                    }
                }
            }
        }
        return ACCESS_ABSTAIN;
    }

    private Collection<ConfigAttribute> buildOrgSecurityConfigAttributes(List<DefaultOrg> orgs, boolean granted) {
        Collection<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
        for (DefaultOrg org : orgs) {
            SecurityConfigAttribute attr = new SecurityConfigAttribute(AttributeType.org, granted, org.getCompanyId());
            attr.setMember(org);
            list.add(attr);
        }
        return list;
    }
}